namespace SubhadraSolutions.Sharp.Logging.Common
{
    using SubhadraSolutions.Sharp.Logging.Contracts;
    using SubhadraSolutions.Sharp.Logging.LogItems;
    using SubhadraSolutions.Sharp.Utils.Data.Common;
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public class LogStoreItemDataReader : AbstractEnumeratorDataReader<LogStoreItem>, ILoggerDataReader
    {
        #region Fields

        private ExpandoLogItem _expando;
        private string _processInstanceName;

        #endregion Fields

        #region Constructors

        public LogStoreItemDataReader()
        {
            ContextProperties = new List<string>();
            DynamicProperties = new List<string>();
            IgnoreLogEntry = false;
        }

        #endregion Constructors

        #region Properties

        public List<string> ContextProperties
        {
            get;
            set;
        }

        public List<string> DynamicProperties
        {
            get;
            set;
        }

        public bool IgnoreLogEntry
        {
            get;
            set;
        }

        public bool IsInitialized
        {
            get;
            private set;
        }

        #endregion Properties

        #region Indexers

        public override object this[int i]
        {
            get
            {
                if (i == 0)
                {
                    return SequenceNumber;
                }
                if (!IgnoreLogEntry && i == ColumnNames.Count - 1)
                {
                    return current.LogEntry;
                }
                if (_processInstanceName == null)
                {
                    i++;
                }
                if (i > 6 && i <= 6 + ContextProperties.Count)
                {
                    return getContextProperty(i - 7);
                }
                if (i > 6 + ContextProperties.Count &&
                    i <= 6 + ContextProperties.Count + DynamicProperties.Count)
                {
                    return getDynamicProperty(i - (7 + ContextProperties.Count));
                }

                switch (i)
                {
                    case 1:
                        return _processInstanceName;

                    case 2:
                        return current.Severity.ToString();

                    case 3:
                        return current.Categories.ToString();

                    case 4:
                        return current.TimeStamp;

                    case 5:
                        return current.ThreadId;

                    case 6:
                        return current.ThreadName;
                }
                return null;
            }
        }

        #endregion Indexers

        #region Methods

        public override Type GetFieldType(int i)
        {
            if (i == 0)
            {
                return typeof(long);
            }
            if (_processInstanceName == null)
            {
                i++;
            }
            switch (i)
            {
                case 1:
                    return typeof(string);

                case 2:
                    return typeof(string);
                
                case 3:
                    return typeof(string);

                case 4:
                    return typeof(DateTime);

                case 5:
                    return typeof(int);

                case 6:
                    return typeof(string);
            }
            return typeof(object);
        }

        public void Initialize()
        {
            if (!IsInitialized)
            {
                initializeProtected();
                IsInitialized = true;
            }
        }

        protected override bool readProtected()
        {
            bool canRead = base.readProtected();
            _expando = canRead ? (current.LogEntry as ExpandoLogItem) : null;
            return canRead;
        }

        public void SetProcessInstanceName(string name)
        {
            _processInstanceName = string.IsNullOrWhiteSpace(name) ? null : name;
        }

        protected virtual void initializeProtected()
        {
            ColumnNames.Clear();
            ColumnNames.Add("SNo");
            if (_processInstanceName != null)
            {
                ColumnNames.Add("ProcessInstanceName");
            }
            ColumnNames.Add("LogType");
            ColumnNames.Add("Category");
            ColumnNames.Add("TimeStamp");
            ColumnNames.Add("ThreadId");
            ColumnNames.Add("ThreadName");

            //ColumnNames.Add("Thread CategoryName");
            ColumnNames.AddRange(ContextProperties);
            ColumnNames.AddRange(DynamicProperties);
            if (!IgnoreLogEntry)
            {
                ColumnNames.Add("LogEntry");
            }
        }

        private object getContextProperty(int propertyIndex)
        {
            if (current.ContextValues != null)
            {
                if (current.ContextValues.Keys.Count > propertyIndex)
                {
                    var key = this.ContextProperties[propertyIndex];
                    object value = null;
                    current.ContextValues.TryGetValue(key, out value);
                    return value;
                }
            }
            return null;
        }

        private object getDynamicProperty(int propertyIndex)
        {
            if (_expando == null)
            {
                return null;
            }
            object o;
            _expando.TryGetValue(DynamicProperties[propertyIndex], out o);
            return o;
        }

        #endregion Methods
    }
}